#include "graphics.h"
#include "player.h"
#include <ClanLib/core.h>
#include <vector>

Graphics::Graphics(CL_DisplayWindow* displayWindow) {
	this->window = displayWindow;
	this->gc = window->get_gc();
	this->sprites = new std::vector<DrawableObject>();
	this->resourceManager = ResourceManager::getInstance();
	this->gameModel = GameModel::getInstance();
	this->font = new CL_Font(gc, "Tahoma", 24);

	this->valuesSizeX = static_cast<int> (RESOLUTION_HEIGHT / TILE_SIZE + 1);
	this->valuesSizeY = static_cast<int> (RESOLUTION_WIDTH / TILE_SIZE + 1);
}

Graphics::~Graphics(void) {
	delete (sprites);
}

void Graphics::addToDraw(CL_Sprite* sprite, int posX, int posY) {
	DrawableObject object(sprite, posX, posY);
	sprites->push_back(object);
}

void ::Graphics::drawBackground() {
	ResourceManager* resourcemanager = ResourceManager::getInstance();
	Player* player = resourcemanager->getPlayer();
	CL_Sprite * img = resourcemanager->getGameSprite(BACKGROUND_CLOUDS);
	float playerPosX = player->getPosX();
	float playerPosY = player->getPosY();
	int width = resourcemanager->getLevel()->getWidth() * 30;
	int height = resourcemanager->getLevel()->getHeight() * 30;

	static int xOffset = 0;

	for (int i = 0; i < width * 2; i += 150) {
		for (int j = 0; j < height * 2; j += 150) {
			img->draw(gc, i - ((int) (playerPosX * 30)) - xOffset, j
					- ((int) (playerPosY * 30)));
		}
	}

	xOffset = (xOffset + 1) % 150;
}

void Graphics::draw() {
	gc.clear(CL_Colorf(CL_Colorf::black));

	//hintergrund zeichnen
	drawBackground();

	DrawableObject item;
	for (unsigned int i = 0; i < sprites->size(); i++) {
		item = sprites->at(i);
		item.getImage()->draw(gc, item.getPosX(), item.getPosY());
	}

	// user interface zeichnen
	drawLevelAndPlayer();
	if (resourceManager->getPlayer()->getHasHabanero()) {
		drawPlayerBoundingBox();
	}
	drawUserInterface();
	drawEnemies();
	window->flip(1);
	// liste der zu rendernden objekte loeschen
	sprites->clear();
}

void Graphics::drawLevelAndPlayer() {
	Level* level = resourceManager->getLevel();
	Player* player = resourceManager->getPlayer();
	float playerPosX = player->getPosX();
	float playerPosY = player->getPosY();

	float currPosX = 0;
	float currPosY = 0;
	int offsetX =
			static_cast<int> ((playerPosX - static_cast<int> (playerPosX))
					* TILE_SIZE);
	int offsetY =
			static_cast<int> ((playerPosY - static_cast<int> (playerPosY))
					* TILE_SIZE);

	int columnCount = static_cast<int> ((RESOLUTION_WIDTH / TILE_SIZE) + 2);
	int rowCount = static_cast<int> ((RESOLUTION_HEIGHT / TILE_SIZE) + 2);

	for (int i = 0; i < rowCount; i++) {
		for (int j = 0; j < columnCount; j++) {
			int tileX = static_cast<int> (((playerPosX) - (columnCount / 2))
					+ j);
			int tileY = static_cast<int> (((playerPosY) - (rowCount / 2)) + i);

			if (tileX >= 0 && tileY >= 0 && tileX <= level->getWidth() && tileY
					<= level->getHeight()) {
				char object = level->getTile(tileX, tileY);

				if (object != PLAYER_START || object != OBJECT_AIR) {
					CL_Sprite * img = resourceManager->getGameSprite(object);
					if (img != NULL) {
						img->draw(gc, currPosX - offsetX, currPosY - offsetY);
					}
				}
			}
			currPosX += TILE_SIZE;
		}
		currPosY += TILE_SIZE;
		currPosX = 0;
	}

	int playMidX = static_cast<int> ((RESOLUTION_WIDTH / 2) + TILE_SIZE);
	int playMidY = static_cast<int> ((RESOLUTION_HEIGHT / 2) + TILE_SIZE);

	// debugausgabe "kasterl um maxerl"
	//drawPlayerBoundingBox();

	// maxerl zeichnen
	CL_Sprite * img;
	if (player->getLastPlayerDirection() == PlayerDirection::RIGHT) {
		if (player->getPlayerState() == PlayerDirection::NONE) {
			img = player->getPlayerImage();
		} else
			img = player->getPlayerAnimatedImage();
	} else if (player->getLastPlayerDirection() == PlayerDirection::LEFT) {
		if (player->getPlayerState() == PlayerDirection::NONE) {
			img = player->getPlayerImage_mirrored();
		} else
			img = player->getPlayerAnimatedImage_mirrored();
	}

	if (img != NULL) {
		img->draw(gc, playMidX, playMidY);
	}
}

void Graphics::drawPlayerBoundingBox() {
	int playMidX = static_cast<int> ((RESOLUTION_WIDTH / 2) + TILE_SIZE);
	int playMidY = static_cast<int> ((RESOLUTION_HEIGHT / 2) + TILE_SIZE);

	CL_Draw::fill(gc, CL_Rectf(static_cast<float> (playMidX),
			static_cast<float> (playMidY), CL_Sizef(30, 30)), CL_Colorf(1.0f,
			1.0f, 1.0f, 0.7f));
	/*
	 // Oben
	 CL_Draw::fill(gc, CL_Rectf(static_cast<float> (playMidX + 14.5
	 - COLLISION_HORIZONTAL * 30), static_cast<float> (playMidY),
	 CL_Sizef(1, 1)), CL_Colorf(1.0f, 0.0f, 0.0f, 1.0f));
	 CL_Draw::fill(gc, CL_Rectf(static_cast<float> (playMidX + 14.5
	 + COLLISION_HORIZONTAL * 30), static_cast<float> (playMidY),
	 CL_Sizef(1, 1)), CL_Colorf(1.0f, 0.0f, 0.0f, 1.0f));

	 // Unten
	 CL_Draw::fill(gc, CL_Rectf(static_cast<float> (playMidX + 14.5
	 - COLLISION_HORIZONTAL * 30), static_cast<float> (playMidY + 29),
	 CL_Sizef(1, 1)), CL_Colorf(1.0f, 0.0f, 0.0f, 1.0f));
	 CL_Draw::fill(gc, CL_Rectf(static_cast<float> (playMidX + 14.5
	 + COLLISION_HORIZONTAL * 30), static_cast<float> (playMidY + 29),
	 CL_Sizef(1, 1)), CL_Colorf(1.0f, 0.0f, 0.0f, 1.0f));

	 // Links
	 CL_Draw::fill(gc, CL_Rectf(static_cast<float> (playMidX),
	 static_cast<float> (playMidY + 14.5 - COLLISION_VERTICAL * 30),
	 CL_Sizef(1, 1)), CL_Colorf(1.0f, 0.0f, 0.0f, 1.0f));
	 CL_Draw::fill(gc, CL_Rectf(static_cast<float> (playMidX),
	 static_cast<float> (playMidY + 14.5 + COLLISION_VERTICAL * 30),
	 CL_Sizef(1, 1)), CL_Colorf(1.0f, 0.0f, 0.0f, 1.0f));

	 // Rechts
	 CL_Draw::fill(gc, CL_Rectf(static_cast<float> (playMidX + 29),
	 static_cast<float> (playMidY + 14.5 - COLLISION_VERTICAL * 30),
	 CL_Sizef(1.0f, 1.0f)), CL_Colorf(1.0f, 0.0f, 0.0f, 1.0f));

	 CL_Draw::fill(gc, CL_Rectf(static_cast<float> (playMidX + 29),
	 static_cast<float> (playMidY + 14.5 + COLLISION_VERTICAL * 30),
	 CL_Sizef(1.0f, 1.0f)), CL_Colorf(1.0f, 0.0f, 0.0f, 1.0f));
	 */
}

void Graphics::drawUserInterface() {
	Player* player = resourceManager->getPlayer();

	CL_String hitpoints = cl_format("HITPOINTS: %1", player->getHitpoints());
	CL_String score = cl_format("SCORE: %1", player->getScore());
	CL_String lives = cl_format("LIVES: %1", player->getLifes());
	CL_String habanero = cl_format("HABANERO IS ACTIVE %1",
			player->getHabaneroTimer());
	CL_String playerstate = cl_format("STATE: %1", player->getPlayerState());

	// hintergrund zeichnen
	CL_Draw::fill(gc, CL_Rectf(0, 0, CL_Sizef(
			static_cast<float> (RESOLUTION_WIDTH), 30.0f)), CL_Colorf(1.0f,
			1.0f, 1.0f, 0.9f));
	CL_Draw::fill(gc, CL_Rectf(0, 30, CL_Sizef(
			static_cast<float> (RESOLUTION_WIDTH), 1.0f)), CL_Colorf(0.0f,
			0.0f, 0.0f, 0.9f));

	// text zeichnen
	font->draw_text(gc, 350, 22, lives, CL_Colorf::black);
	font->draw_text(gc, 600, 22, score, CL_Colorf::black);

	if (resourceManager->getPlayer()->getHasHabanero()) {
		font->draw_text(gc, 50, 22, habanero, CL_Colorf::red);
	}

	if (player->getIsDead()) {
		CL_Draw::fill(gc, CL_Rectf(0, 0, CL_Sizef(
				static_cast<float> (RESOLUTION_WIDTH),
				static_cast<float> (RESOLUTION_WIDTH))), CL_Colorf(1.0f, 0, 0,
				0.4f));
	}
}

void Graphics::drawEnemies() {
	const std::vector<Enemy*> enemies = gameModel->getEnemies();
	Enemy* enemy;
	Player* player = resourceManager->getPlayer();
	CL_Sprite* enemyimage = resourceManager->getEnemy()->getImage();

	float playerPosX = player->getPosX();
	float playerPosY = player->getPosY();

	float maxDistanceX = RESOLUTION_WIDTH / 2;
	float maxDistanceY = RESOLUTION_WIDTH / 2;

	int playMidX = static_cast<int> ((RESOLUTION_WIDTH / 2) + TILE_SIZE);
	int playMidY = static_cast<int> ((RESOLUTION_HEIGHT / 2) + TILE_SIZE);

	// alle gegner durchgehn
	for (unsigned int i = 0; i < enemies.size(); i++) {
		enemy = enemies.at(i);
		// distanzen zum spieler ausrechnen
		float distanceToPlayerPosX = enemy->getPosX() * TILE_SIZE - playerPosX
				* TILE_SIZE;
		float distanceToPlayerPosY = enemy->getPosY() * TILE_SIZE - playerPosY
				* TILE_SIZE;

		// wenn gegner in zeichenbereich liegt
		if (abs(distanceToPlayerPosX < maxDistanceX) && abs(
				distanceToPlayerPosY < maxDistanceY)) {
			if (enemyimage != NULL) {
				// Achtung! TILE_SIZE wird von xpos abgezogen, passt besser
				enemyimage->draw(gc, static_cast<int> (distanceToPlayerPosX
						+ playMidX - TILE_SIZE),
						static_cast<int> (distanceToPlayerPosY + playMidY));
			}
		}
	}
}

void Graphics::drawEndingScreen() {
	gc.clear(CL_Colorf(CL_Colorf::black));
	//hintergrund zeichnen
	drawBackground();

	Player* player = resourceManager->getPlayer();

	CL_String score = cl_format("SCORE: %1", player->getScore());
	CL_String lives = cl_format("LIVES: %1", player->getLifes());
	CL_String finalScore = cl_format("FINAL SCORE: %1", player->getScore()
			* player->getLifes());

	// text zeichnen
	font->draw_text(gc, 300, 230, lives, CL_Colorf::black);
	font->draw_text(gc, 300, 270, score, CL_Colorf::black);
	font->draw_text(gc, 300, 310, finalScore, CL_Colorf::black);
	window->flip(1);

}

void Graphics::drawGameOverScreen() {
	gc.clear(CL_Colorf(CL_Colorf::black));
	//hintergrund zeichnen
	drawBackground();
	CL_String gameOver("GAME OVER!");
	font->draw_text(gc, 300, 270, gameOver, CL_Colorf::red);
	window->flip(1);
}

